package me.zhengjie.modules.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import me.zhengjie.modules.system.domain.Dept;
import me.zhengjie.modules.system.domain.FlowConfig;
import me.zhengjie.modules.system.domain.User;
import me.zhengjie.modules.system.mapper.FlowConfigMapper;
import me.zhengjie.modules.system.mapper.UserMapper;
import me.zhengjie.modules.system.service.DeptService;
import me.zhengjie.modules.system.service.FlowConfigService;
import me.zhengjie.modules.system.service.ProcessTaskService;
import me.zhengjie.modules.system.service.UserService;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.*;

@Service
@RequiredArgsConstructor
public class ProcessTaskServiceImpl implements ProcessTaskService {

    private final ProcessEngine processEngine;
    private final RuntimeService runtimeService;
    private final HistoryService historyService;
    private final RepositoryService repositoryService;
    private final UserService userService;
    private final DeptService deptService;
    private final FlowConfigMapper flowConfigMapper;

    @Override
    public Map<String, Object> getMyInitiation(Long id) {
        List<Map<String, Object>> lists = new ArrayList<>();
        //todo 流程
        List<HistoricProcessInstance> historicProcessInstances = historyService.createHistoricProcessInstanceQuery().startedBy(id.toString()).list();
        for (HistoricProcessInstance instance : historicProcessInstances) {
            Map<String, Object> historicalMap = new HashMap<>();
            FlowConfig flowConfig = flowConfigMapper.findByFlowId(instance.getProcessDefinitionId());
            if (flowConfig != null) {
                historicalMap.put("id", instance.getId());
                historicalMap.put("flowId", instance.getProcessDefinitionId());
                historicalMap.put("flowName", instance.getProcessDefinitionName());
                historicalMap.put("flowType", flowConfig.getFlowTypes().getFlowType());
                historicalMap.put("version", instance.getProcessDefinitionVersion());
                historicalMap.put("startTime", instance.getStartTime());
                if (instance.getEndTime() == null) {
                    historicalMap.put("durationInMillis", new Date().getTime() - instance.getStartTime().getTime());
                    ProcessInstance runningInstance = runtimeService.createProcessInstanceQuery().processInstanceId(instance.getId()).singleResult();
                    if (runningInstance.getBusinessStatus() == null) {
                        historicalMap.put("flowStatus", "进行中");
                    } else {
                        historicalMap.put("flowStatus", runningInstance.getBusinessStatus());
                    }
                    HistoricActivityInstance activityInstance = historyService.createHistoricActivityInstanceQuery().processInstanceId(instance.getId()).unfinished().singleResult();
                    historicalMap.put("activity", activityInstance.getActivityName());
                } else {
                    historicalMap.put("durationInMillis", instance.getDurationInMillis());
                    //historicalMap.put("endTime", instance.getEndTime());
                    historicalMap.put("activity", null);
                    if (instance.getDeleteReason() != null) {
                        historicalMap.put("flowStatus", "撤销");
                    } else {
                        historicalMap.put("flowStatus", "完成");
                    }
                }
                lists.add(historicalMap);
            }
        }

        Map<String, Object> outerMap = new HashMap<>();
        outerMap.put("content", lists);
        return outerMap;
    }

    @Override
    public Map<String, Object> getMyTodoList(Long id) {
        TaskService taskService = processEngine.getTaskService();
        List<Task> taskList = taskService.createTaskQuery().taskAssignee(id.toString()).active().list();
        List<Map<String, Object>> lists = new ArrayList<>();
        for (Task task : taskList) {
            Map<String, Object> taskMap = new HashMap<>();
            User user = userService.findById(Long.parseLong(task.getAssignee()));
            Dept dept = deptService.findById(user.getDeptId());
            FlowConfig flowConfig = flowConfigMapper.findByFlowId(task.getProcessDefinitionId());
            Map<String, Object> variables = taskService.getVariables(task.getId());
            taskMap.put("id", task.getId());
            taskMap.put("flowName", flowConfig.getFlowName());
            taskMap.put("flowType", flowConfig.getFlowTypes().getFlowType());
            taskMap.put("currentNode", task.getName());
            taskMap.put("version", ((org.flowable.task.service.impl.persistence.entity.TaskEntity) task).getRevision());
            taskMap.put("approve", user.getNickName());
            taskMap.put("receiveTime", task.getCreateTime());
            taskMap.put("approveDept", dept.getName());
            taskMap.put("startUserId", variables.get("startUserId"));
            taskMap.put("remark", variables.get("remark"));
            lists.add(taskMap);
        }
        Map<String, Object> outerMap = new HashMap<>();
        outerMap.put("content", lists);
        return outerMap;
    }

    @Override
    public Map<String, Object> getMyCC(Long id) {
        return null;
    }


    @Override
    public void revokeTask(Map<String, Object> resource) {
        String processInstanceId = resource.get("id").toString();
        String reason = resource.get("reason").toString();
        List<HistoricTaskInstance> completedTasks = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).finished().list();
        if (!completedTasks.isEmpty()) {
            throw new RuntimeException("流程已在进行中，无法撤回");
        }
        runtimeService.setVariable(processInstanceId, "approvalStatus", "revoked");
        runtimeService.deleteProcessInstance(processInstanceId, reason);
    }

    @Override
    public void completeTask(String taskId) {
        Map<String, Object> variables = new HashMap<>();
        variables.put("approvalStatus", "approved");
        TaskService taskService = processEngine.getTaskService();
        taskService.complete(taskId, variables);
    }

    @Override
    public void refundTask(Map<String, Object> resource) {
        String taskId = resource.get("taskId").toString();
        String reason = resource.get("reason").toString();
        TaskService taskService = processEngine.getTaskService();
        taskService.setVariable(taskId, "approvalStatus", "refund");
        taskService.setVariable(taskId, "refundReason", reason);
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        String processInstanceId = task.getProcessInstanceId();
        List<HistoricActivityInstance> activities = historyService
                .createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricActivityInstanceStartTime()
                .asc()
                .list();
        if (!activities.isEmpty()) {
            taskService.complete(taskId);
            String initialActivityId = activities.get(0).getActivityId();
            runtimeService.createChangeActivityStateBuilder()
                    .processInstanceId(processInstanceId)
                    .moveActivityIdTo(task.getTaskDefinitionKey(), initialActivityId)
                    .changeState();
        }
    }
}
